#include "display7seg_drv.h"

#if (DISP7SEG_C_USE_DEMUX == pdON)
static u8 offset = 0; 	// Deslogamento do primeira linha de endereço do demux.
static u8 qtdCMux = 0; 	// Quantidade de endereços contêm o demux
#endif

// -------------------------------------------------------------------------------------------------------------------
// Descrição: 	Inicializa a porta do processador para controlar os módulos de 7 segmentos
// Parametro:	Nenhum
// Retorna:		Nada
// -------------------------------------------------------------------------------------------------------------------
void disp7seg_SetupPorts(void) {
	u8 x;

	#if (DISP7SEG_C_USE_DEMUX == pdON)
	// Quantide de deslocamento do primeiro bit do controle de acionamento de módulo
	//	Ex: Se for BIT_2 offset 2
	offset = 0;
	for (x=0;x<8;x++) { if (x&DISP7SEG_C_INIT) { offset = x; break; }}

	// Calcula a mascara das linhas de endereços do demux de acordo com a quantidade de displays
	//	Ex: Se for 3 linhas o mask = 0b111
	u8 mask = 0;
	for (x=0;x<DISP7SEG_N_MODULE;x++) mask |= x;

	// Quantidade de linhas de endereços do demux
	//	Ex: Se for 3 linhas o qtdCMux = 3
	qtdCMux = 0;
	for (x=0;x<8;x++) if (mask&_BV(x)) qtdCMux++;
	#endif

	// Pinos para os leds 1 a 8 como saida
	//sbi(DISP7SEG_DIR, DISP7SEG_LED1);

	DISP7SEG_DIR |= (
		_BV(DISP7SEG_LED1) |
		_BV(DISP7SEG_LED2) |
		_BV(DISP7SEG_LED3) |
		_BV(DISP7SEG_LED4) |
		_BV(DISP7SEG_LED5) |
		_BV(DISP7SEG_LED6) |
		_BV(DISP7SEG_LED7) |
		_BV(DISP7SEG_LED8)
	);

	// desligar os leds dos segmentos
	DISP7SEG_PORT = (
		_BV(DISP7SEG_LED1) |
		_BV(DISP7SEG_LED2) |
		_BV(DISP7SEG_LED3) |
		_BV(DISP7SEG_LED4) |
		_BV(DISP7SEG_LED5) |
		_BV(DISP7SEG_LED6) |
		_BV(DISP7SEG_LED7) |
		_BV(DISP7SEG_LED8)
	);

	// Pinos para os comuns dos leds como saida e desligados
	u8 bit = DISP7SEG_C_INIT;
	for (x=0;x<DISP7SEG_N_MODULE;x++) {
		sbi(DISP7SEG_C_DIR, bit);
		cbi(DISP7SEG_C_PORT, bit);
		bit++;
	}
}

void disp7seg_WriteSeg(int value) {
	#if (DISP7SEG_COMMON == DISP7SEG_COMMON_ANODE)
	// Não testado
	if (value & 0x80)	cbi(DISP7SEG_PORT, DISP7SEG_LED1); else sbi(DISP7SEG_PORT, DISP7SEG_LED1);
	if (value & 0x40)	cbi(DISP7SEG_PORT, DISP7SEG_LED2); else sbi(DISP7SEG_PORT, DISP7SEG_LED2);
	if (value & 0x20)	cbi(DISP7SEG_PORT, DISP7SEG_LED3); else sbi(DISP7SEG_PORT, DISP7SEG_LED3);
	if (value & 0x10)	cbi(DISP7SEG_PORT, DISP7SEG_LED4); else sbi(DISP7SEG_PORT, DISP7SEG_LED4);
	if (value & 0x8)	cbi(DISP7SEG_PORT, DISP7SEG_LED5); else sbi(DISP7SEG_PORT, DISP7SEG_LED5);
	if (value & 0x4)	cbi(DISP7SEG_PORT, DISP7SEG_LED6); else sbi(DISP7SEG_PORT, DISP7SEG_LED6);
	if (value & 0x2)	cbi(DISP7SEG_PORT, DISP7SEG_LED7); else sbi(DISP7SEG_PORT, DISP7SEG_LED7);
	if (value & 0x1)	cbi(DISP7SEG_PORT, DISP7SEG_LED8); else sbi(DISP7SEG_PORT, DISP7SEG_LED8);
	#else
	if (value & 0x80)	sbi(DISP7SEG_PORT, DISP7SEG_LED1); else cbi(DISP7SEG_PORT, DISP7SEG_LED1);
	if (value & 0x40)	sbi(DISP7SEG_PORT, DISP7SEG_LED2); else cbi(DISP7SEG_PORT, DISP7SEG_LED2);
	if (value & 0x20)	sbi(DISP7SEG_PORT, DISP7SEG_LED3); else cbi(DISP7SEG_PORT, DISP7SEG_LED3);
	if (value & 0x10)	sbi(DISP7SEG_PORT, DISP7SEG_LED4); else cbi(DISP7SEG_PORT, DISP7SEG_LED4);
	if (value & 0x8)	sbi(DISP7SEG_PORT, DISP7SEG_LED5); else cbi(DISP7SEG_PORT, DISP7SEG_LED5);
	if (value & 0x4)	sbi(DISP7SEG_PORT, DISP7SEG_LED6); else cbi(DISP7SEG_PORT, DISP7SEG_LED6);
	if (value & 0x2)	sbi(DISP7SEG_PORT, DISP7SEG_LED7); else cbi(DISP7SEG_PORT, DISP7SEG_LED7);
	if (value & 0x1)	sbi(DISP7SEG_PORT, DISP7SEG_LED8); else cbi(DISP7SEG_PORT, DISP7SEG_LED8);
	#endif
}

// -------------------------------------------------------------------------------------------------------------------
// Descrição: 	Liga somente o módulo desejado desligando os demais
// Parametro:	module: Módulo que deseja acionar, valores de 0 a DISP7SEG_N_MODULE-1, valor -1 deslisga todos
// Retorna:		Nada
// -------------------------------------------------------------------------------------------------------------------
void disp7seg_SetModule(int module) {
	// se usar um demux na linha de seleção
	#if (DISP7SEG_C_USE_DEMUX == pdON)
	u8 bit = offset; // pega o primeiro bit de endereço do demux
	// Fazer para todos os bits do module
	u8 x; for (x=0;x<qtdCMux;x++) {
		// Cada bit do module corresponde a cada bit do endereço do demux.
		// Se o bit do module estiver acionado vamos ligar o pino do endereço, senão manter desligado
		if (module&_BV(x)) sbi(DISP7SEG_C_PORT, bit); else cbi(DISP7SEG_C_PORT, bit);
		bit++; // ir para o próximo bit
	}
	#else
	// não testado
	u8 x;
	u8 bit = DISP7SEG_C_INIT;
	for (x=0;x<DISP7SEG_N_MODULE;x++) {
		#if (DISP7SEG_COMMON == DISP7SEG_COMMON_ANODE)
		if (x==module) cbi(DISP7SEG_C_PORT, bit); else  sbi(DISP7SEG_C_PORT, bit);
		#else
		if (x==module) sbi(DISP7SEG_C_PORT, bit); else  cbi(DISP7SEG_C_PORT, bit);
		#endif
		bit++;
	}
	#endif
}
